package com.amigo.online.provider.search.service.impl;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.stream.Collectors;

import afu.org.checkerframework.checker.igj.qual.I;
import com.amigo.online.common.param.result.*;
import com.amigo.online.provider.search.mapper.SearchMapper;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.TermsResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.amigo.online.common.base.security.LocalUser;
import com.amigo.online.common.param.dto.query.MerchantGoodsDto;
import com.amigo.online.common.param.dto.query.Searchparam;
import com.amigo.online.common.param.result.VideoInfo.VideoUserInfo;
import com.amigo.online.provider.search.async.AsyncHotWord;
import com.amigo.online.provider.search.common.SolrCoreEnum;
import com.amigo.online.provider.search.controller.SolrController;
import com.amigo.online.provider.search.model.SearchResponseResult;
import com.amigo.online.provider.search.service.SolrService;
import com.amigo.online.provider.search.service.UserFeignService;
import com.amigo.online.provider.search.service.VideoFeignService;
import com.amigo.online.provider.search.util.Underline2CamelStringUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

@Service
public class SolrServiceImpl implements SolrService {

    @Autowired
    AsyncHotWord asyncHotWord;

    @Autowired
    private SearchMapper searchMapper;

    @Autowired
    private SolrClient client;

    @Autowired
    private UserFeignService userFeignService;

    @Autowired
    private VideoFeignService videoFeignService;

    public static final ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(5);

    private Logger log = LoggerFactory.getLogger(SolrController.class);

    @Override
    public JSONObject search(Searchparam searchparam) throws Exception {
        insertHotWord(searchparam);

        LocalUserInfo localUser = LocalUser.getUser();
        SolrDocumentList userResults = searchUser(searchparam);
        // 登陆用户是否关注了视频发布者
        if (localUser != null) {
            System.out.println("userId：" + localUser.getUser().getId());
            List<Long> followedIds = getFollowedIds(localUser.getUser().getId(), userResults.stream()
                    .map(user -> Long.valueOf(user.get("id").toString())).collect(Collectors.toList()));
            System.out.println("followedIds => " + followedIds);
            for (SolrDocument userDocument : userResults) {
                Long userDocumentId = null;
                System.out.println(userDocument.get("id").getClass().getName());
                if (userDocument.get("id") instanceof String) {
                    userDocumentId = Long.valueOf((String) userDocument.get("id"));
                } else if (userDocument.get("id") instanceof Long) {
                    userDocumentId = (Long) userDocument.get("id");
                } else if (userDocument.get("id") instanceof Integer) {
                    userDocumentId = ((Integer) userDocument.get("id")).longValue();
                }
                System.out.println("userDocumentId:" + userDocumentId);
                userDocument.put("followed",
                        followedIds == null ? false : followedIds.contains(userDocumentId));
            }
        }

        // 视频查询
        SolrDocumentList videoResults = searchVideo(searchparam);
        // 把music,user构建到videoInfo
        List<VideoInfo> videoInfoList = buildVideoInfo(videoResults);

        JSONObject jsonObj = new JSONObject();
        //2次排序
        int temp = 0;

        for(int i = userResults.size() - 1; i >= 0; i--){
            if(userResults.get(i).get("nickname")==null){
                userResults.remove(userResults.get(i));
            }
        }

        for(int j = searchparam.getQ().replaceAll("\\\\","").length();j > 0 ;j --) {
            for (int i = temp; i < userResults.size(); i++) {
                String nickname = (String) userResults.get(i).get("nickname");
                    nickname = nickname.toLowerCase();
                    if (nickname.contains(searchparam.getQ().toLowerCase().replaceAll("\\\\", "").substring(0, j))) {
                        SolrDocument sd = userResults.get(temp);
                        SolrDocument sd1 = userResults.get(i);
                        userResults.set(temp, sd1);
                        userResults.set(i, sd);
                        ++temp;
                    }
            }
        }

        int end = Integer.parseInt(searchparam.getRows());
        if(end > userResults.size()){
            end = userResults.size();
        }
        SolrDocumentList newUserList = new SolrDocumentList();
        if(Integer.valueOf(searchparam.getStart()) >= userResults.size()){
            newUserList = null;
        }else {
            for(int i = 0 ; i < end; i ++){
                if(i >= Integer.valueOf(searchparam.getStart())){
                    newUserList.add(userResults.get(i));
                }
            }
        }



        jsonObj.put("user", newUserList);
        jsonObj.put("video", videoInfoList);
        return jsonObj;
    }

//    @Override
//    public JSONObject search(Searchparam searchparam) throws Exception {
//        insertHotWord(searchparam.getQ());
//
//        LocalUserInfo localUser = LocalUser.getUser();
//        List<UserInfo> userInfo = searchMapper.userId(Long.parseLong(searchparam.getQ()));
//        List<UserInfo> userResults = null;
//        if(userInfo == null) {
//            userResults = searchMapper.user(searchparam.getQ(), Integer.parseInt(searchparam.getStart()), Integer.parseInt(searchparam.getRows()));
//        }
//        // 登陆用户是否关注了视频发布者
//        if (localUser != null) {
//            System.out.println("userId：" + localUser.getUser().getId());
//
//            List<Long> userIdList = new ArrayList<>();
//            for (UserInfo u:userInfo
//                 ) {
//                userIdList.add(u.getId());
//            }
//            List<Long> followedIds = getFollowedIds(localUser.getUser().getId(), userIdList);
//            System.out.println("followedIds => " + followedIds);
//            for (UserInfo userDocument : userResults) {
//                Long userDocumentId = userDocument.getId();
////                System.out.println(userDocument.get("id").getClass().getName());
////                if (userDocument.get("id") instanceof String) {
////                    userDocumentId = Long.valueOf((String) userDocument.get("id"));
////                } else if (userDocument.get("id") instanceof Long) {
////                    userDocumentId = (Long) userDocument.get("id");
////                } else if (userDocument.get("id") instanceof Integer) {
////                    userDocumentId = ((Integer) userDocument.get("id")).longValue();
////                }
//                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(userDocument);
//                System.out.println("userDocumentId:" + userDocumentId);
//                jsonObject.put("followed",
//                        followedIds == null ? false : followedIds.contains(userDocumentId));
//            }
//        }

//        // 视频查询
//        List<VideoInfo> videoInfoList = searchMapper.selectVideo(searchparam.getQ(),searchparam.getStart(),searchparam.getRows());
//
//        JSONObject jsonObj = new JSONObject();
//        jsonObj.put("user", userResults);
//        jsonObj.put("video", videoInfoList);
//        return jsonObj;
//    }

    @Override
    public SearchResponseResult getHotWord() {
        List<JSONObject> arrayList = new ArrayList<JSONObject>();
        // 创建查询参数以及设定的查询参数
        SolrQuery query = new SolrQuery();

        query.set("q", "*:*");
        query.set("start", 0); // 记录开始位置
        query.set("rows", 10); // 查询的行数
        query.set("qt", "/terms");
        // parameters settings for terms requesthandler
        // 参考（refer to）http://wiki.apache.org/solr/termscomponent
        query.set("terms", "true");
        query.set("terms.fl", "hotword");
//        query.set("terms.regex.flag", "case_insensitive");
        query.set("terms.sort", "count");// terms.sort={count|index} -如果count，各种各样的条款术语的频率（最高计数第一）。
        query.set("terms.regex","[a-zA-Z0-9]*[a-zA-Z][a-zA-Z0-9]*");//热搜限定不能为纯数字
        // 如果index，索引顺序返回条款。默认是count
        // 查询并获取相应的结果！
        QueryResponse response = null;
        try {
            response = client.query(SolrCoreEnum.hotword.toString(), query);
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 获取相关的查询结果
        if (response != null) {
            TermsResponse termsResponse = response.getTermsResponse();
            if (termsResponse != null) {
                Map<String, List<TermsResponse.Term>> termsMap = termsResponse.getTermMap();
                for (Map.Entry<String, List<TermsResponse.Term>> termsEntry : termsMap.entrySet()) {
                    List<TermsResponse.Term> termList = termsEntry.getValue();
                    for (TermsResponse.Term term : termList) {
                        JSONObject jsonObj = new JSONObject();
                        jsonObj.put("hotWord", term.getTerm().replace("\\",""));
                        log.info("==============================================");
                        log.info(term.getTerm());
                        log.info(term.getTerm().replace("\\",""));
                        jsonObj.put("count", term.getFrequency());
                        arrayList.add(jsonObj);
                    }
                }
            }
        }
        SearchResponseResult rs = new SearchResponseResult();
        rs.setData(arrayList);
        return rs;
    }

    @Override
    public JSONObject merchantSearch(Searchparam searchparam) {
        List<JSONObject> merchantResults = searchMerchant(searchparam);
        List<JSONObject> goodsResults = searchGoods(searchparam);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("merchant", merchantResults);
        jsonObject.put("goods", goodsResults);
        return jsonObject;
    }

    @Override
    public JSONObject merchantGoodsSearch(MerchantGoodsDto searchparam) {
        List<JSONObject> goodsResults = searchGoods(searchparam);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("goods", goodsResults);
        return jsonObject;
    }

    private List<JSONObject> searchMerchant(Searchparam searchparam) {
        SolrQuery merchantQ = new SolrQuery();
        StringBuilder merchantSb = new StringBuilder();
        merchantSb.append("item_keywords:").append(searchparam.getQ()).append(" || ").append("merchant_name:")
                .append(searchparam.getQ()).append("*");
        merchantQ.set("q", merchantSb.toString());
        merchantQ.addFilterQuery("status : 2");
        merchantQ.addFilterQuery("deleted : 0");
        merchantQ.set("start", searchparam.getStart()); // 记录开始位置
        merchantQ.set("rows", searchparam.getRows()); // 查询的行数

        merchantQ.setRows(Integer.valueOf(searchparam.getRows()));
        log.info("merchant的查询条件为:{}", merchantQ.toString());
        SolrDocumentList merchantResults = new SolrDocumentList();
        List<JSONObject> merchantJsons = new ArrayList<>();
        try {
            merchantResults = client.query(SolrCoreEnum.merchant.toString(), merchantQ).getResults();
            if (merchantResults != null && merchantResults.size() != 0) {
                // 根据merchantId查出最多3个goods
                List<String> merchantIds = merchantResults.stream().map(rs -> (String) rs.get("id"))
                        .collect(Collectors.toList());
                SolrQuery query = new SolrQuery();
                // query.set("sort", "feedback desc");
                query.set("start", 0); // 记录开始位置
                query.set("rows", 3); // 查询的行数
                String ids = merchantIds.stream().collect(Collectors.joining(",", "(", ")"));
                query.set("q", "merchant_id : " + ids);
                query.set("sort", "feedback desc");
                SolrDocumentList goodsDocumentList = client.query(SolrCoreEnum.goods.toString(), query).getResults();
                merchantJsons = solrDocumentList2JSONObjectList(merchantResults);
                List<JSONObject> goodsJsons = solrDocumentList2JSONObjectList(goodsDocumentList);
                // 最多 10*3
                for (JSONObject merchantJson : merchantJsons) {
                    List<JSONObject> currentMerchantGoodsList = new ArrayList<>();
                    for (JSONObject goodsJson : goodsJsons) {
                        if (merchantJson.get("id").equals(goodsJson.get("merchantId"))) {
                            currentMerchantGoodsList.add(goodsJson);
                        }
                    }
                    merchantJson.put("goods", currentMerchantGoodsList);
                }
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info("merchant的查询结果数量为:{}", merchantResults == null ? "exception" : merchantResults.size());
        return merchantJsons;
    }

    private List<JSONObject> solrDocumentList2JSONObjectList(SolrDocumentList goodsDocumentList) {
        List<JSONObject> rs = new ArrayList<>();
        if (goodsDocumentList != null) {
            for (SolrDocument solrDocument : goodsDocumentList) {
                rs.add(solrDocument2JSONObject(solrDocument));
            }
        }
        return rs;

    }

    private JSONObject solrDocument2JSONObject(SolrDocument solrDocument) {
        JSONObject json = new JSONObject();
        Set<String> keySet = solrDocument.keySet();
        for (String key : keySet) {
            json.put(Underline2CamelStringUtil.camelName(key), solrDocument.get(key));
        }
        return json;
    }

    private List<JSONObject> searchGoods(MerchantGoodsDto searchparam) {
        SolrQuery goodsQ = new SolrQuery();
        StringBuilder goodsSb = new StringBuilder();
        goodsSb.append("title:").append(searchparam.getQ()).append(" || ").append("title:*").append(searchparam.getQ())
                .append("*"); // 中文分词或者巴西名模糊匹配
        goodsQ.set("q", goodsSb.toString());
        goodsQ.setFilterQueries("status : 2");
        goodsQ.addFilterQuery("deleted : 0");
        goodsQ.setFilterQueries("merchant_id : " + searchparam.getMerchantId());
        goodsQ.set("sort", "id desc");
        goodsQ.setStart(Integer.valueOf(searchparam.getStart()));
        goodsQ.setRows(Integer.valueOf(searchparam.getRows()));
        log.info("merchant的查询条件为:{}", goodsQ.toString());
        SolrDocumentList merchantResults = null;
        try {
            merchantResults = client.query(SolrCoreEnum.goods.toString(), goodsQ).getResults();
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info("goods的查询结果数量为:{}", merchantResults == null ? "exception" : merchantResults.size());
        return solrDocumentList2JSONObjectList(merchantResults);
    }

    private List<JSONObject> searchGoods(Searchparam searchparam) {
        SolrQuery goodsQ = new SolrQuery();
        StringBuilder goodsSb = new StringBuilder();
        goodsSb.append("title:").append(searchparam.getQ()).append(" || ").append("title:*").append(searchparam.getQ())
                .append("*"); // 中文分词或者巴西名模糊匹配
        goodsQ.set("q", goodsSb.toString());
        goodsQ.setFilterQueries("status : 2");
        goodsQ.setFilterQueries("deleted : 0");
        goodsQ.set("sort", "id desc");
        goodsQ.setStart(Integer.valueOf(searchparam.getStart()));
        goodsQ.setRows(Integer.valueOf(searchparam.getRows()));
        log.info("goods的查询条件为:{}", goodsQ.toString());
        SolrDocumentList merchantResults = null;
        try {
            merchantResults = client.query(SolrCoreEnum.goods.toString(), goodsQ).getResults();
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info("goods的查询结果数量为:{}", merchantResults == null ? "exception" : merchantResults.size());
        return solrDocumentList2JSONObjectList(merchantResults);
    }

    private List<VideoInfo> buildVideoInfo(SolrDocumentList videoResults) throws SolrServerException, IOException {
        List<VideoInfo> videoInfoList = new ArrayList<>();
        if (!videoResults.isEmpty()) {
            List<String> musicIdsStr = new ArrayList<>();// 查出来视频中的musicIds(solr使用,类型为String)
            List<Long> videoIds = new ArrayList<>();// 查出来视频中的videoIds
            List<Long> userIds = new ArrayList<>();// 查出来视频中的userIds
            List<String> userIdsStr = new ArrayList<>();// 查出来视频中的userIds(solr使用,类型为String)
            for (SolrDocument solrDocument : videoResults) {
                Long music_id = (Long) solrDocument.get("music_id");
                Long user_id = (Long) solrDocument.get("user_id");
                String video_id = (String) solrDocument.get("id");
                musicIdsStr.add(String.valueOf(music_id));
                userIds.add(user_id);
                userIdsStr.add(String.valueOf(user_id));
                videoIds.add(Long.valueOf(video_id));
            }
            // 查出video中的music中信息
            SolrDocumentList musicSolr = musicIdsStr.isEmpty() ? new SolrDocumentList()
                    : client.getById("music", musicIdsStr);
            Map<String, MusicInfo> musicSolrMap = new HashMap<>();
            for (SolrDocument solrDocument : musicSolr) {
                MusicInfo music = new MusicInfo();
                transMap2Bean(solrDocument, music);
                musicSolrMap.put(solrDocument.get("id") + "", music);
            }
            // 查出视频发布者的信息
            SolrDocumentList userSolr = userIdsStr.isEmpty() ? new SolrDocumentList()
                    : client.getById("user", userIdsStr);
            Map<Object, VideoUserInfo> userSolrMap = new HashMap<>();
            for (SolrDocument solrDocument : userSolr) {
                VideoUserInfo vui = new VideoUserInfo();
                vui.setAccount((String) solrDocument.get("account"));
                vui.setAvatar((String) solrDocument.get("avatar"));
                vui.setNickname((String) solrDocument.get("nickname"));
                vui.setUped(false);
                vui.setFollowed(false);
                userSolrMap.put(Long.valueOf(solrDocument.get("id") + ""), vui);
            }
            // 把music,user构建到videoInfo
            for (SolrDocument solrDocument : videoResults) {
                VideoInfo videoInfo = new VideoInfo();
                transMap2Bean(solrDocument, videoInfo);
                // user构建到videoInfo
                if (userSolrMap != null) {
                    VideoUserInfo temp_user = new VideoUserInfo();
                    temp_user.setAccount(userSolrMap.get(solrDocument.get("user_id")).getAccount());
                    temp_user.setAvatar(userSolrMap.get(solrDocument.get("user_id")).getAvatar());
                    temp_user.setNickname(userSolrMap.get(solrDocument.get("user_id")).getNickname());
                    temp_user.setFollowed(false);
                    temp_user.setUped(false);
                    videoInfo.setUser(temp_user);
                }
                // music构建到videoInfo
                if (musicSolrMap != null) {
                    videoInfo.setMusic(musicSolrMap.get(solrDocument.get("music_id")));
                }
                videoInfoList.add(videoInfo);
            }

            setFollowAndUpStattus(videoInfoList, videoIds, userIds);
        }
        return videoInfoList;
    }

    private void setFollowAndUpStattus(List<VideoInfo> videoInfoList, List<Long> videoIds, List<Long> userIds) {
        LocalUserInfo localUser = LocalUser.getUser();
        if (localUser != null) {
            /* 登陆用户是否关注了视频发布者 */
            UserInfo user = localUser.getUser();
            List<Long> followedIds = getFollowedIds(user.getId(), userIds);

            /* 登陆用户是否点赞了视频 */
            // upedIdsObj为登陆用户在videoIds这些视频中已经点赞了的
            Object upedIdsObj = videoFeignService.getUpByVideoId(user.getId(), videoIds).getBody().getData();
            ObjectMapper x = new ObjectMapper();
            List<Long> upedIds = x.convertValue(upedIdsObj, new TypeReference<List<Long>>() {
            });
            for (VideoInfo videoInfo : videoInfoList) {
                VideoUserInfo temp_user = videoInfo.getUser();
                temp_user.setUped(upedIds == null ? false : upedIds.contains(videoInfo.getId()));
                temp_user.setFollowed(followedIds == null ? false : followedIds.contains(videoInfo.getUserId()));
            }
        }
    }

    // 判断userId在userIds中有多少用户关注了自己，返回关注自己的id集合
    private List<Long> getFollowedIds(Long userId, List<Long> userIds) {
        // followedIdsObj为登陆用户在userIds这些用户中已经关注了的
        Object followedIdsObj = userFeignService.getfollowedByUserId(userId, userIds).getBody().getData();
        ObjectMapper x = new ObjectMapper();
        return x.convertValue(followedIdsObj, new TypeReference<List<Long>>() {
        });
    }

    private SolrDocumentList searchVideo(Searchparam searchparam) throws SolrServerException, IOException {
        SolrQuery videoQ = new SolrQuery();
        StringBuilder videoSb = new StringBuilder();
        // content包括content
        videoSb.append("item_keywords:").append(searchparam.getQ()).append(" || ").append("content:")
                .append(searchparam.getQ()).append("*");
        videoQ.set("q", videoSb.toString());
        videoQ.setFilterQueries("deleted : 0");
        videoQ.setStart(Integer.valueOf(searchparam.getStart()));
        videoQ.setRows(Integer.valueOf(searchparam.getRows()));
        log.info("video的查询条件为:{}", videoQ.getQuery());
        SolrDocumentList videoResults = client.query(SolrCoreEnum.video.toString(), videoQ).getResults();
        log.info("video的查询结果数量为:{}", videoResults.size());
        return videoResults;
    }

    /**
     * 从solr中通关搜索条件查询用户信息
     *
     * @param searchparam
     * @return
     * @throws SolrServerException
     * @throws IOException
     */
    private SolrDocumentList searchUser(Searchparam searchparam) throws SolrServerException, IOException {
        SolrQuery userQ = new SolrQuery();
        StringBuilder userSb = new StringBuilder();
        // item_keywords包括nickname,account
        if(searchparam.getQ().length()>1) {
            userSb.append("item_keywords:").append(searchparam.getQ()).append(" || ").append("nickname:")
                    .append(searchparam.getQ()).append(" || ").append("id:")
                    .append(searchparam.getQ().substring(1, searchparam.getQ().length())).append("*");
        } else {
            userSb.append("item_keywords:").append(searchparam.getQ()).append(" || ").append("nickname:")
                    .append(searchparam.getQ()).append(" || ").append("id:")
                    .append(searchparam.getQ()).append("*");
        }
        userQ.set("q", userSb.toString());
//        userQ.setStart(Integer.valueOf(searchparam.getStart()));
//        userQ.setRows(Integer.valueOf(searchparam.getRows()));
        //由于solr排序异常，在此手动排序，后来的人需要调整solr排序功能
        userQ.setStart(Integer.valueOf(0));
        userQ.setRows(Integer.valueOf(200));
        log.info("user的查询条件为:{}", userQ.getQuery());
        SolrDocumentList userResults = client.query(SolrCoreEnum.user.toString(), userQ).getResults();
        log.info("user的查询结果数量为:{}", userResults.size());
        return userResults;
    }

    private void insertHotWord(Searchparam searchparam) throws InterruptedException {
        queue.put(searchparam.getQ());
        asyncHotWord.insertHotWord();
    }

//    private void insertHotWord(String word) throws InterruptedException {
//        Long time = System.currentTimeMillis()/1000;
//        if(searchMapper.selectHotWord(word) > 0){
//            searchMapper.addNumHotWord(word,time);
//        }else
//        searchMapper.insertHotWord(word,time);
//    }

    private void transMap2Bean(Map<String, Object> map, Object obj) {
        try {
            // 解决solr中的id与vo类中id类型不一致的问题
            map.put("id", Long.valueOf((String) map.get("id")));
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                if (map.containsKey(key)) {
                    Object value = map.get(key);
                    // 得到property对应的setter方法
                    Method setter = property.getWriteMethod();
                    System.out.println(setter.getName() + "---" + value);
                    setter.invoke(obj, value);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
